package com.bckj.fastboot.flow.process;

import com.bckj.fastboot.flow.model.*;
import lombok.extern.slf4j.Slf4j;

import java.util.Stack;

@Slf4j
public class BpmnSetupVisitor implements BpmnVisitor {

    private final BpmnProcess bpmnProcess;
    private final Stack<BpmnParallelGateway> parallelGatewayStartStack = new Stack<>();

    public BpmnSetupVisitor(BpmnProcess bpmnProcess) {
        this.bpmnProcess = bpmnProcess;
    }

    @Override
    public void visit(BpmnStartEvent startEvent) {
        outgoingFlow(startEvent);
    }

    @Override
    public void visit(BpmnServiceTask serviceTask) {
        outgoingFlow(serviceTask);
    }

    @Override
    public void visit(BpmnSequenceFlow sequenceFlow) {
        //获取target
        BpmnElement targetElement = bpmnProcess.getElementById(sequenceFlow.getTargetRef());
        if (targetElement != null) {
            targetElement.accept(this);
        }
    }

    @Override
    public void visit(BpmnEndEvent endEvent) {

    }

    @Override
    public void visit(BpmnExclusiveGateway exclusiveGateway) {
        outgoingFlow(exclusiveGateway);
    }

    @Override
    public void visit(BpmnParallelGateway parallelGateway) {
        parallelGateway.validation();
        if (parallelGateway.isStart()) {
            parallelGatewayStartStack.push(parallelGateway);
            for (BpmnSequenceFlow flow : parallelGateway.getOutgoingFlows()) {
               visit(flow);
            }
        } else {
            if (parallelGatewayStartStack.isEmpty()) {
                log.error("parallelGatewayStartStack is empty");
                return;
            }
            BpmnParallelGateway startGateway = parallelGatewayStartStack.pop();
            startGateway.setEndId(parallelGateway.getId());
            parallelGateway.setStartId(startGateway.getId());
            visit(parallelGateway.getOutgoingFlows().get(0));
        }
    }

    @Override
    public void visit(BpmnCallActivity element) {

    }

    private void outgoingFlow(BpmnElement element) {
        log.debug("SequenceFlow " + element.getType() + ": " + element.getId());
        for (BpmnSequenceFlow flow : element.getOutgoingFlows()) {
            visit(flow);
        }
    }
}
